package cn.ycxy.lbl.member.service.impl;

import cn.hutool.core.util.IdUtil;
import cn.ycxy.lbl.common.exception.BusinessException;
import cn.ycxy.lbl.common.exception.enums.ResponseEnum;
import cn.ycxy.lbl.common.pojo.CsAuthenticationInfo;
import cn.ycxy.lbl.common.utils.JwtTokenUtils;
import cn.ycxy.lbl.member.consumer.IMRegisterConsumer;
import cn.ycxy.lbl.member.dao.RoleDao;
import cn.ycxy.lbl.member.dao.UserDao;
import cn.ycxy.lbl.member.service.IUserService;
import cn.ycxy.lbl.member.utils.SecurityContextUtils;
import cn.ycxy.lbl.member.utils.WXDecodeUtil;
import cn.ycxy.lbl.pojo.member.domain.User;
import cn.ycxy.lbl.pojo.member.dto.UserLoginDTO;
import cn.ycxy.lbl.pojo.member.vo.LoginSuccessVO;
import cn.ycxy.lbl.pojo.member.vo.UserDetailVO;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.easemob.im.server.EMService;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@DubboService
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserDao, User> implements IUserService {

    @Value("${weixin.appid}")
    private String appid;
    @Value("${weixin.secret}")
    private String secret;
    @Value("${weixin.urlPre}")
    private String urlPre;
    @Value("${jwt.tokenHead}")
    private String jwtTokenHead;
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private JwtTokenUtils jwtTokenUtils;
    @Autowired
    private RoleDao roleDao;
    @Autowired
    private UserDao userDao;
    //@Autowired
    @Autowired
    private RabbitTemplate rabbitTemplate;
    /**
     * 用户执行登录
     * @param dto
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public LoginSuccessVO doLogin(UserLoginDTO dto) {
        String openid = dto.getOpenid();
        String sessionKey = dto.getSessionKey();
        // 走第一步, 微信登录授权获取sessionKey
        if (openid == null || sessionKey == null){
            String url = urlPre + "?appid=" + appid + "&secret=" + secret + "&js_code=" + dto.getCode() + "&grant_type=authorization_code";
            log.info("请求url为: {}", url);
            String restBody = restTemplate.getForObject(url, String.class);
            JSONObject map = JSONObject.parseObject(restBody);
            if (null == map || !map.containsKey("openid") || !map.containsKey("session_key")){
                throw new BusinessException(ResponseEnum.LOGIN_ERROR);
            }
            openid = (String)map.get("openid");
            sessionKey = (String)map.get("session_key");
        }

        LoginSuccessVO loginSuccessVO = new LoginSuccessVO()
                .setOpenid(openid)
                .setSessionKey(sessionKey);
        //查询用户是否已注册
        QueryWrapper<User> qw = new QueryWrapper<>();
        qw.select("id","nickname","avatar","phone","weixin_openid","session_key","password","approve_status","college","is_enable","login_count");
        qw.eq("weixin_openid", openid);
        User user = getOne(qw);
        if (null == user){
            //用户未注册
            if (dto.getIv() == null || dto.getEncryptedData() == null){
                return loginSuccessVO;
            }
            //使用微信iv,被加密手机号进行解密, 并进行注册登录
            String json = WXDecodeUtil.deciphering(dto.getEncryptedData(), dto.getIv(), dto.getSessionKey());
            JSONObject jsonObject = JSONObject.parseObject(json);
            user = new User();
            // 生成一个uuid密码, 作为用户登录IM的密码
            user.setPassword(IdUtil.simpleUUID());
            user.setPhone(jsonObject.getString("phoneNumber"));
            user.setWeixinOpenid(openid);
            user.setSessionKey(sessionKey);
            user.setNickname(dto.getNickName());
            user.setLastLoginIp(dto.getIp());
            user.setLastLoginTime(LocalDateTime.now());
            user.setAvatar(dto.getAvatarUrl());
            user.setIsEnable(1);
            if (!save(user)){
                throw new BusinessException(ResponseEnum.LOGIN_ERROR);
            }
            //使用rabbitmq异步发送消息, 注册IM用户用于聊天服务
            rabbitTemplate.convertAndSend(IMRegisterConsumer.CS_MEMBER_EX,
                    IMRegisterConsumer.CS_MEMBER_IM_REGISTER_RK, user);
            log.info("新用户注册成功!id:{}, nickName:{}", user.getId(), user.getNickname());
        }else {
            //已注册, 进行登录更新操作
            user.setLastLoginIp(dto.getIp());
            user.setLastLoginTime(LocalDateTime.now());
            user.setLoginCount(user.getLoginCount()+1);
            updateById(user);
        }
        // 检查账号是否启用
        if (user.getIsEnable() != 1) {
            throw new BusinessException(ResponseEnum.LOGIN_BAN);
        }
        loginSuccessVO.setUserId(user.getId());
        loginSuccessVO.setPhoneNumber(user.getPhone());
        //获取环信IM token
        //String IMToken = emService.token().getUserTokenWithInherit("im"+user.getPhone());
        //log.info("获取IM Token成功, phone:{}, token:{}", user.getPhone(), IMToken);
        loginSuccessVO.setImTokenValue(user.getPassword());
        //获取登录用户角色列表
        //List<String> roles = roleDao.listRolesById(user.getId());
        List<String> roles = new ArrayList<>();
        if (user.getApproveStatus() == 2){
            //认证成功, 才有角色权限
            roles.add("ROLE_user");
            //返回学院名称
            loginSuccessVO.setCollege(user.getCollege());
        }
        CsAuthenticationInfo userInfo = generateFromUser(user, roles);
        String token = jwtTokenUtils.generateToken(userInfo);
        loginSuccessVO.setTokenHeader(jwtTokenHead).setTokenValue(token);
        return loginSuccessVO;
    }

    /**
     * 用户认证成功, 更新token从新加载权限
     * @return
     */
    @Override
    public String loadTokenByUser(){
        CsAuthenticationInfo info = SecurityContextUtils.getUserInfo();
        List<String> authorities = info.getAuthorities();
        authorities.add("ROLE_user");
        info.setAuthorities(authorities);
        return jwtTokenHead + " " + jwtTokenUtils.generateToken(info);
    }

    /**
     * 获取用户部分信息
     * @param id
     * @return
     */
    @Override
    public UserDetailVO getUserDetailById(long id) {
        return userDao.queryUserDetailById(id);
    }


    private CsAuthenticationInfo generateFromUser(User userDetails, List<String> authorityValues){
        CsAuthenticationInfo userInfo=new CsAuthenticationInfo();
        userInfo.setId(userDetails.getId());
        userInfo.setUsername(userDetails.getWeixinOpenid());
        userInfo.setUserType("USER");
        userInfo.setAuthorities(authorityValues);
        return userInfo;

    }
}
